package cn.edu.sgu.www.mhxysy.config;

import cn.edu.sgu.www.mhxysy.config.property.SystemSettingsProperties;
import cn.edu.sgu.www.mhxysy.entity.system.Permission;
import cn.edu.sgu.www.mhxysy.feign.clients.pms.PmsFeignService;
import cn.edu.sgu.www.mhxysy.restful.JsonResult;
import cn.edu.sgu.www.mhxysy.shiro.UserPasswordMatcher;
import cn.edu.sgu.www.mhxysy.shiro.UsernameRealm;
import cn.edu.sgu.www.mhxysy.shiro.filter.PermsFilter;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Apache Shiro配置类
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Configuration
public class ShiroConfig {

    /**
     * 服务名
     */
    @Value("${spring.application.name}")
    private String service;

    private final PmsFeignService feignService;
    private final SystemSettingsProperties systemSettingsProperties;

    @Autowired
    public ShiroConfig(
            PmsFeignService feignService,
            SystemSettingsProperties systemSettingsProperties) {
        this.feignService = feignService;
        this.systemSettingsProperties = systemSettingsProperties;
    }

    @Bean
    public UsernameRealm usernameRealm(UserPasswordMatcher passwordMatcher) {
        UsernameRealm usernameRealm = new UsernameRealm();

        usernameRealm.setCredentialsMatcher(passwordMatcher);

        return usernameRealm;
    }

    /**
     * 配置Shiro过滤器工厂
     * @param securityManager 安全管理器
     * @return ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 注册安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        /*
         * 设置登录页面的地址
         * 当用户访问认证资源的时候，如果用户没有登录，就会跳转到指定的页面
         */
        shiroFilterFactoryBean.setLoginUrl("/login.html");

        // 定义资源访问规则
        Map<String, String> filterMap = new LinkedHashMap<>();

        // 1、允许不登录访问的资源
        filterMap.put("/js/*", "anon");
        filterMap.put("/css/*", "anon");
        filterMap.put("/json/*", "anon");
        filterMap.put("/error/*", "anon");
        filterMap.put("/easyui/*", "anon");
        filterMap.put("/images/*", "anon");
        filterMap.put("/main.html", "anon");
        filterMap.put("/login.html", "anon");
        filterMap.put("/favicon.ico", "anon");

        // 2、必须登录认证才能访问的资源
        filterMap.put("/", "authc");
        filterMap.put("/html/*", "authc");
        filterMap.put("/index.html", "authc");
        // knife4j
        filterMap.put("/doc.html", "authc");
        filterMap.put("/v2/api-docs", "authc");
        filterMap.put("/swagger-resources", "authc");

        // 3、开启了鉴权：把接口url交给shiro定义的过滤器perms处理
        if (systemSettingsProperties.isEnableAuthorization()) {
            // 添加自定义过滤器
            Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();

            filters.put("perms", new PermsFilter());

            shiroFilterFactoryBean.setFilters(filters);

            // 查询所有非匿名子接口权限
            JsonResult<List<Permission>> jsonResult = feignService.selectPermissions(service);

            if (jsonResult.isSuccess()) {
                List<Permission> permissions = jsonResult.getData();

                // 把所有权限的url交给自定义过滤器AuthorizationFilter处理
                if (CollectionUtils.isNotEmpty(permissions)) {
                    for (Permission permission : permissions) {
                        filterMap.put(permission.getUrl(), "perms[" + permission.getValue() + "]");
                    }
                }
            }
        }

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        return shiroFilterFactoryBean;
    }

}